home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / Sample Code / AppsToGo / Kibitz / Offscreen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-24  |  11.7 KB  |  384 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        offscreen.c
  5. ** Written by:  Eric Soldan
  6. **
  7. ** Copyright © 1991-1992 Apple Computer, Inc.
  8. ** All rights reserved. */
  9.  
  10.  
  11.  
  12. /*****************************************************************************/
  13.  
  14.  
  15.  
  16. #include "Kibitz.h"                /* Get the Kibitz includes/typedefs, etc.    */
  17. #include "KibitzCommon.h"        /* Get the stuff in common with rez.        */
  18. #include "Kibitz.protos"        /* Get the prototypes for Kibitz.            */
  19.  
  20. #ifndef __ERRORS__
  21. #include "Errors.h"
  22. #endif
  23.  
  24. #ifndef __GWLAYERS__
  25. #include <GWLayers.h>
  26. #endif
  27.  
  28. #ifndef __RESOURCES__
  29. #include <Resources.h>
  30. #endif
  31.  
  32. #ifndef __UTILITIES__
  33. #include <Utilities.h>
  34. #endif
  35.  
  36.  
  37.  
  38. static short        gDepth, gPiece;
  39. static CTabHandle    gCtab;
  40. static Rect            gPieceRect;
  41. static RgnHandle    gColorRgn, gTestRgn;
  42.  
  43.  
  44.  
  45. /*****************************************************************************/
  46.  
  47.  
  48.  
  49. LayerObj            gBoardLayer;
  50. short                gClearSquare;
  51. extern CIconHandle    gPieceCIcon[26];
  52.  
  53. static OSErr    PieceLayerProc(LayerObj theLayer, short message);
  54. static OSErr    BoardLayerProc(LayerObj theLayer, short message);
  55. static void        PlotWithShadow(short x, short y);
  56.  
  57.  
  58.  
  59. /*****************************************************************************/
  60.  
  61.  
  62.  
  63. #pragma segment Config
  64. OSErr    InitOffscreen(void)
  65. {
  66.     RgnHandle    colorRgn;
  67.     short        depth;
  68.     OSErr        err;
  69.  
  70.     gClearSquare = 0;        /* Regular board imaging as default. */
  71.  
  72.     colorRgn = ScreenDepthRegion(8);
  73.     depth = (EmptyRgn(colorRgn)) ? 1 : 8;
  74.     DisposeRgn(colorRgn);
  75.  
  76.     err = NewLayer(&gBoardLayer, nil, BoardLayerProc, nil, depth, 0);
  77.         /* We create boardLayer at initialization time.  This layer will be
  78.         ** used to image the board off-screen.  Note that the layer has its own
  79.         ** layerProc.  The kLayerInit action doesn't call the default layerInit.
  80.         ** This custom layerProc uses just the size of the above GWorld to
  81.         ** determine the size of the bitmap it creates, so this layer isn't
  82.         ** necessarily the same depth as the above layer.  If there is no above
  83.         ** layer, then this custom layerProc needs to return paramErr for the
  84.         ** kLayerInit message, just as the default LayerProc does. */
  85.  
  86.     return(err);
  87. }
  88.  
  89.  
  90.  
  91. /*****************************************************************************/
  92.  
  93.  
  94.  
  95. #pragma segment Config
  96. void    MoveThePiece(FileRecHndl frHndl, short fromSq, Rect fromRect, Point fromLoc, Point *toLoc)
  97. {
  98.     WindowPtr        window, keepPort;
  99.     LayerObj        windowLayer, pieceLayer;
  100.     short            dx, dy, adx, ady, ticksForMove, tickDiff, update;
  101.     unsigned long    startTick;
  102.     Point            lastLoc, mouseLoc, pt;
  103.  
  104.     lastLoc.h = lastLoc.v = 0x4000;
  105.         /* Make sure that the first position gets updated.  We want a last mouse
  106.         ** location that is different than whatever the user would have clicked. */
  107.  
  108.     keepPort = SetFilePort(frHndl);
  109.     GetPort(&window);
  110.  
  111.     ImageDocument(frHndl, true);
  112.  
  113.     NewLayer(&windowLayer, nil, nil, window, 8, 0);
  114.         /* Create the layer object related to the window.  If NewLayer fails,
  115.         ** windowLayer is set to nil. */
  116.     (*windowLayer)->dstRect = BoardRect();
  117.         /* pieceLayer isn't the same size as the window's portRect.  By setting
  118.         ** windowLayer's dstRect, we change the area that the two layers map
  119.         ** to.  dstRect is set nil by NewLayer, and if it is left nil, then
  120.         ** the portRect is used for mapping.  Since we only want to map into
  121.         ** the window for the board, we set dstRect to just that portion of
  122.         ** the window. */
  123.     gClearSquare = fromSq;
  124.     gPiece       = (*frHndl)->doc.theBoard[fromSq];
  125.     ImageDocument(frHndl, true);
  126.     gClearSquare = 0;
  127.  
  128.     gTestRgn  = NewRgn();
  129.     gColorRgn = ScreenDepthRegion(8);        /* Screen of 8-bit or greater get color icon. */
  130.     pt.h = pt.v = 0;
  131.     GlobalToLocal(&pt);
  132.     OffsetRgn(gColorRgn, pt.h, pt.v);        /* Localize the area that gets color icons. */
  133.  
  134.     NewLayer(&pieceLayer, windowLayer, PieceLayerProc, nil, 8, 0);
  135.         /* pieceLayer is created, and it maps to the board area of windowLayer.
  136.         ** Note that windowLayer is a parameter for pieceLayer.  If windowLayer
  137.         ** failed to get created, then this call will return a paramErr.  This
  138.         ** is because if you don't state a port, pixmap, or bitmap, the default
  139.         ** layerProc (which PieceLayerProc calls) uses the above layer to
  140.         ** determine the size and depth of an off-screen GWorld it automatically
  141.         ** creates.  If there is also no above layer, then there is nothing that
  142.         ** can be used as a basis for the GWorld, and that results in a paramErr. */
  143.  
  144.     InsertLayer(gBoardLayer, windowLayer, 2);
  145.         /* Connect board layer in as the background layer. */
  146.     InvalLayer(windowLayer, fromRect, false);
  147.         /* On first update, redraw square where piece was picked up. */
  148.  
  149.     if (toLoc->h != 0x4000) {        /* If we have a start and end point, slide the piece. */
  150.         startTick = TickCount();
  151.         dx = adx = toLoc->h - fromLoc.h;
  152.         if (adx < 0) adx = -adx;
  153.         dy = ady = toLoc->v - fromLoc.v;
  154.         if (ady < 0) ady = -ady;
  155.         ticksForMove = (adx + ady) / 3;
  156.         if (ticksForMove > 30) ticksForMove = 30;
  157.             /* The piece slide will take at most half a second. */
  158.     }
  159.  
  160.     for (;;) {
  161.         if (toLoc->h == 0x4000) {        /* If user grabbed the piece, get where the mouse is now. */
  162.             GetMouse(&mouseLoc);
  163.             update = UpdateTime(frHndl, true);
  164.             if (update) DrawTime(frHndl);
  165.             if (update == 2) {
  166.                 if ((*frHndl)->doc.twoPlayer) SendGame(frHndl, kIsMove, nil);
  167.                 AlertIfGameOver(frHndl);
  168.                 lastLoc.h = lastLoc.v = 0x4000;
  169.                 break;
  170.             }
  171.         }
  172.         else {
  173.             tickDiff = TickCount() - startTick;
  174.             if (tickDiff > ticksForMove) tickDiff = ticksForMove;
  175.             mouseLoc.h = fromLoc.h + dx * tickDiff / ticksForMove;
  176.             mouseLoc.v = fromLoc.v + dy * tickDiff / ticksForMove;
  177.                 /* If sliding piece, calculate the new position, based on time. */
  178.         }
  179.         if ((lastLoc.h != mouseLoc.h) || (lastLoc.v != mouseLoc.v)) {
  180.                 /* If new piece position is different than last... */
  181.             lastLoc = mouseLoc;
  182.             gPieceRect = fromRect;
  183.             gPieceRect.right  += 5;            /* Make space for the piece's shadow. */
  184.             gPieceRect.bottom += 5;
  185.             OffsetRect(&gPieceRect, mouseLoc.h - fromLoc.h - 2, mouseLoc.v - fromLoc.v - 2);
  186.                 /* Position the update rect at the new mouse location but offset 2
  187.                 ** up and 2 left.  This offset is so the piece looks like it is
  188.                 ** lifted from the board for the first update. */
  189.             InvalLayer(windowLayer, gPieceRect, true);    /* Mark the area to be updated. */
  190.             UpdateLayer(windowLayer);                    /* DO IT. */
  191.         }
  192.         if (toLoc->h == 0x4000) {        /* If under user control... */
  193.             if (!StillDown()) break;    /* Break if mouse is released. */
  194.         }
  195.         else if (tickDiff == ticksForMove) break;
  196.             /* If piece being slid, break when it gets there. */
  197.     }
  198.  
  199.     DetachLayer(gBoardLayer);
  200.         /* Keep this permanent layer from being disposed of. */
  201.     DisposeThisAndBelowLayers(windowLayer);
  202.         /* Dispose of the layers and associated data. */
  203.     DisposeRgn(gColorRgn);
  204.     DisposeRgn(gTestRgn);
  205.  
  206.     SetPort(keepPort);
  207.     *toLoc = lastLoc;        /* Return where the piece was dropped. */
  208. }
  209.  
  210.  
  211.  
  212. /*****************************************************************************/
  213.  
  214.  
  215.  
  216. #pragma segment Config
  217. static OSErr    PieceLayerProc(LayerObj theLayer, short message)
  218. {
  219.     OSErr    err;
  220.     GrafPtr    thisPort;
  221.  
  222.     err = noErr;
  223.     switch (message) {
  224.         case kLayerInit:
  225.             gCtab = nil;
  226.                 /* We will need a color table if the depth is greater than 1, and
  227.                 ** we succeed in creating the pixMap for the layer.  Assume that
  228.                 ** these conditions won't be met, and initialize the color table
  229.                 ** reference to nil. */
  230.             err = DefaultLayerProc(theLayer, kLayerInit);
  231.             if (!err) {
  232.                 thisPort = (*theLayer)->layerPort;
  233.                 gDepth = 1;
  234.                 if (thisPort->portBits.rowBytes & 0x8000)
  235.                     gDepth = (*(((CGrafPtr)thisPort)->portPixMap))->pixelSize;
  236.                 if (gDepth != 1) gCtab = GetCTable(64 + 8);
  237.                     /* We need a color table for the shadow if depth is greater than 1. */
  238.             }
  239.             break;
  240.         case kLayerDispose:
  241.             err = DefaultLayerProc(theLayer, kLayerDispose);
  242.                 /* Do the standard dispose behavior. */
  243.             if (gCtab) DisposeCTable(gCtab);
  244.                 /* Dispose of the color table for the piece shadow, if we have one. */
  245.             break;
  246.         case kLayerUpdate:
  247.             DefaultLayerProc(theLayer, kLayerUpdate);
  248.             SetLayerWorld(theLayer);
  249.             PlotWithShadow(gPieceRect.left, gPieceRect.top);
  250.                 /* Draw the piece and shadow into the piece layer in the new position. */
  251.             ResetLayerWorld(theLayer);
  252.             break;
  253.         default:
  254.             err = DefaultLayerProc(theLayer, message);
  255.                 /* For future messages, use the default behavior. */
  256.             break;
  257.     }
  258.  
  259.     return(err);
  260. }
  261.  
  262.  
  263.  
  264. /*****************************************************************************/
  265.  
  266.  
  267.  
  268. #pragma segment Config
  269. static OSErr    BoardLayerProc(LayerObj theLayer, short message)
  270. {
  271.     OSErr        err;
  272.     Rect        boardRect;
  273.     GWorldPtr    layerWorld;
  274.     CGrafPtr    keepPort;
  275.     GDHandle    keepGDevice;
  276.  
  277.     switch (message) {
  278.         case kLayerInit:
  279.             boardRect = BoardRect();
  280.             err = NewGWorld(&layerWorld, (*theLayer)->layerDepth, &boardRect, nil, nil, 0);
  281.             if (!err) {        /* If we succeeded at creating the GWorld... */
  282.                 (*theLayer)->layerOwnsPort = true;
  283.                 GetGWorld(&keepPort, &keepGDevice);        /* To get the GDevice. */
  284.                 (*theLayer)->layerPort    = (GrafPtr)layerWorld;
  285.                 (*theLayer)->layerGDevice = keepGDevice;
  286.                 SetLayerWorld(theLayer);
  287.                 SetOrigin(boardRect.left, boardRect.top);
  288.                 EraseRect(&boardRect);
  289.                     /* Pre-clear the bitmap before imaging into it. */
  290.                 ImageBoardLines(1, kBoardHOffset, kBoardVOffset);
  291.                     /* Pre-image the lines dividing the squares. */
  292.                 ResetLayerWorld(theLayer);
  293.             }
  294.             break;
  295.         default:
  296.             err = DefaultLayerProc(theLayer, message);
  297.                 /* Default behavior for everything else. */
  298.             break;
  299.     }
  300.  
  301.     return(err);
  302. }
  303.  
  304.  
  305.  
  306. /*****************************************************************************/
  307.  
  308.  
  309.  
  310. #pragma segment Config
  311. void    PlotWithShadow(short x, short y)
  312. {
  313.     GrafPtr        curPort;
  314.     Handle        shadowHndl;
  315.     short        pieceShadow;
  316.     ResType        iconType;
  317.     Rect        iconRect, destRect;
  318.     char        hstate;
  319.     PixMap        shadowPixMap;
  320.  
  321.     iconType = (gDepth == 1) ? 'ICON' : 'icl8';
  322.     if ((pieceShadow = gPiece) < 0) pieceShadow = -pieceShadow;
  323.     shadowHndl = GetResource(iconType, 400 + pieceShadow);
  324.     hstate = LockHandleHigh(shadowHndl);
  325.  
  326.     SetRect(&iconRect, 0, 0, 32, 32);
  327.     shadowPixMap.baseAddr   = *shadowHndl;
  328.     shadowPixMap.rowBytes   = (iconType == 'ICON') ? 4 : 0x8020;
  329.     shadowPixMap.bounds     = iconRect;
  330.     shadowPixMap.pmVersion  = 0;
  331.     shadowPixMap.packType   = 0;
  332.     shadowPixMap.packSize   = 0;
  333.     shadowPixMap.hRes       = 0x00480000;
  334.     shadowPixMap.vRes       = 0x00480000;
  335.     shadowPixMap.pixelType  = 0;
  336.     shadowPixMap.pixelSize  = 8;
  337.     shadowPixMap.cmpCount   = 1;
  338.     shadowPixMap.cmpSize    = 8;
  339.     shadowPixMap.planeBytes = 0;
  340.     shadowPixMap.pmTable    = gCtab;
  341.     shadowPixMap.pmReserved = 0;
  342.  
  343.     destRect.bottom = (destRect.top  = y + 5) + 32;
  344.     destRect.right  = (destRect.left = x + 5) + 32;
  345.         /* Add 5 to offset the shadow. */
  346.  
  347.     GetPort(&curPort);
  348.     CopyBits((BitMapPtr)&shadowPixMap, &(curPort->portBits), &iconRect, &destRect, srcOr, nil);
  349.     HSetState(shadowHndl, hstate);
  350.  
  351.     if (!gPieceCIcon[gPiece + KING])
  352.         gPieceCIcon[gPiece + KING] = ReadCIcon(gPiece + KING + 257);
  353.     if (!gPieceCIcon[gPiece + KING + 13])
  354.         gPieceCIcon[gPiece + KING + 13] = ReadCIcon(gPiece + KING + 13 + 257);
  355.  
  356.     OffsetRect(&destRect, -5, -5);
  357.         /* 5 was added for the shadow.  This undoes that. */
  358.  
  359.     if (!RectInRgn(&destRect, gColorRgn))        /* If 1-bit, draw b/w icon. */
  360.         DrawCIconByDepth(gPieceCIcon[gPiece + KING], destRect, 1, true);
  361.  
  362.     else {                                    /* Draw some combo of color and b/w icon. */
  363.         RectRgn(gTestRgn, &destRect);
  364.         SectRgn(gColorRgn, gTestRgn, gTestRgn);
  365.         if ((*gTestRgn)->rgnSize == 10) {
  366.             if (EqualRect(&((*gTestRgn)->rgnBBox), &destRect)) {        /* All color. */
  367.                 DrawCIconByDepth(gPieceCIcon[gPiece + KING + 13], destRect, 8, true);
  368.                 return;
  369.             }
  370.         }
  371.         SetClip(gTestRgn);
  372.         DrawCIconByDepth(gPieceCIcon[gPiece + KING + 13], destRect, 8, true);    /* Color part. */
  373.         RectRgn(gTestRgn, &destRect);
  374.         XorRgn(gColorRgn, gTestRgn, gTestRgn);
  375.         SetClip(gTestRgn);
  376.         DrawCIconByDepth(gPieceCIcon[gPiece + KING], destRect, 1, true);        /* b/w part. */
  377.         SetRectRgn(gTestRgn, -32000, -32000, 32000, 32000);
  378.         SetClip(gTestRgn);
  379.     }
  380. }
  381.  
  382.  
  383.  
  384.